/**
 *	defined the main entry program
 *   VisualGroup JavaScript prototype Classes, version draf
 *  (c) 2008 Bill Vison <vison_ruan@126.com>
 *
 * 	defined ClassLoaderManager Class
 --------------------------------------------------------------------------*/
ClassLoaderManager = Ext.extend(Ext.util.Observable , {
								
	/**
	 * defined the loader classes cache
	 */
	_loaderClassesCache:null,
	
	/**
	 * get the lock for handle
	 */
	_lock:0,
	
	/** 
	 *	@param {object} initialze the main object manager
	 *	@constructor 
	 */
	constructor:function($config) {
		
		// --- defined the unlock state ---
		this._lock = ClassLoaderManager.UNLOCK;
		
		this._loaders = new Ext.util.MixedCollection();
		
		this._allLoadClasses = new Ext.util.MixedCollection();
		
		// --- initialize loader class ---
		this._loaderClassesCache = new LoaderClassesCache();
		
		ClassLoaderManager.superclass.constructor.apply(this, arguments);
		
		// --- add fire event ---
		this.addEvents({
			// --- fire the event for load class complete
			loadComplete : true,
			executeComplete : true
		});
		
		
	},
	
	/**
	 * get the loaderCache 
	 */
	getLoaderClassesCache:function() {
		return this._loaderClassesCache;
	},

	/**
	 * load the classes and execute them , the method will invoke the all defined data
	 */
	loadAndExecute:function() {
		
		// --- add execute method in event ---
		this.addListener("loadComplete",this.execute, this);
		
		// --- set this
		var $this = this;
		var $loaders = this._loaders;
		var $loaderClassesCache = this._loaderClassesCache;
		
	
		// --- defined handle ----
		var $runner = new Ext.util.TaskRunner();
		var $task = {
			run: function() {
				
				var $stop = true;
				var $loader = null;
				try {

					// --- item -> loader
					for (var $i = 0 ; $i < $loaders.getCount() ; $i++) {
						$loader = $loaders.itemAt($i);
						if ($loader.getLoadClasses().length > 0 ) {
							$stop = false;
							break;
						}
					}
					
					
					// --- unlock for loader classesCache ----
					if ($stop && $this._lock == ClassLoaderManager.LOCK) {
						$this._lock = ClassLoaderManager.UNLOCK;
					}
					
					// ---- check the lock ----
					if ($this._lock == ClassLoaderManager.LOCK) {
						return ;
					}

					if ($stop && $loaderClassesCache.getTemporaryLoadClass().length == 0) {
						

						$runner.stop( this );

						// --- fire the complete load ---
						$this.fireEvent("loadComplete");
						

						
					} else {
						
						$this.load();
						// ---- invoke load handle ----
					
					}
				
				} catch ( ex ) {
					
					$runner.stop( this );
					
					if (ex instanceof Exception) {
						alert(ex.getLocalMessage());
					}
					else {
						alert("unknow error occur in [ClassLoaderManager.loadAndExecute] : " + ex);
					}					
			
				} finally {
					
					$loader = null;
				}
				
			},
			interval:1
		}

		$runner.start( $task );



	},
	
	/**
	 * invoke the script loader defined method
	 */
	load : function() {
		
		// ---- defined method for handle after load ----
		function loaderAfterLoadedHandle($scope , $classState) {

			var $loaderClassesCache = this._loaderClassesCache;
			
			try {

				// --- change the state ---
				var $clsState = $loaderClassesCache.get( $classState.className );
				$clsState.dependentClasses = $classState.dependentClasses;
				$clsState.state = LoadClassState.LOADED;
				$clsState.source = $classState.src;
				$clsState.loader = $scope.getPrefix();
				$clsState.url = $classState.url;

				if ($classState.dependentClasses != undefined && $classState.dependentClasses.length > 0 ) {
					var $dependClasses = $classState.dependentClasses;
					for (var $i = 0 ; $i < $dependClasses.length ; $i++) {
						$loaderClassesCache.addClass( $dependClasses[$i] );
					}
				}
				else {
					ScriptLoaderGlobalHandle.execScriptCode( $clsState.source );
					// --- execute the object ---
					$clsState.state = LoadClassState.EXECUTED;					
				
				}
				$loaderClassesCache.set( $classState.className ,  $clsState);
				
			} catch ( ex ) {
				throw ex;
			}		

		}
		
		// ------- handle the load cache ------------
		var $tmpLoadClass = [];
		var $class = null;
	
		var $classesCache = this._loaderClassesCache;

		while ( ($class = $classesCache.poll()) != null ) {
			$tmpLoadClass.push($class);
		}
		
		// --- set the lock status ---
		this._lock = ClassLoaderManager.LOCK;
		
		// ---- reference this current object ----
		var $this = this;

		// --- invoke the loader start ----
		this._loaders.each(function($item , $index , $length) {
   			var $loader = $item;
			

			var $loaderTmpLoaderClass = $tmpLoadClass;
			
			try {
				/** add the classes */
				$loader.addClasses( $loaderTmpLoaderClass );
				
				$loader.addListener("loaded" , loaderAfterLoadedHandle , $this);
				
				$loader.load();
			
			} catch (ex) {

				if (ex instanceof Exception) {
					alert(ex.getLocalMessage());
				}
				else {
					alert("ClassLoaderManager Defined : " + ex);
				}
				
			} finally {
				
				$loader = null;
				
			}			
		});


		
	},
	
	/**
	 * exetue the class loaded
	 */
	execute : function() {
		
		// --- get the classes cache ---
		try {
			
			ScriptLoaderGlobalHandle.execScript( this._loaderClassesCache.getLoadClasses() );
			
			// --- fire execute script ---
			
			this.fireEvent("executeComplete");
			
		} catch (ex) {
			$msg = "execute : " + ex;
			
			if (Ext != null) {
				Ext.log( $msg );
			} else {
				alert($msg);
			}
			
		} finally {
			
		}
	},
	
	executeForClassState : function($classState) {
		
		ScriptLoaderGlobalHandle.execScriptCode( $classState.source );
					
		// --- execute the object ---
		$classState.state = LoadClassState.EXECUTED;
		
	},

	_loaders:null,
	/**
	 * add defined class loader 
	 */
	addScriptLoader:function($scriptLoader , $baseClassLoader) {
		if ($scriptLoader == null) {
			throw new Exception.SysException("Can not add the empty scripts loader!",null,Exception.NullObjectException);
		}

		try {
			Interface.ensureImplements($scriptLoader, ScriptLoader);	
		} catch (e) {
			throw "Class Implement Error :"+"[ClassLoaderManager.addScriptLoader] , " + e;
		}
		
		try {
			
			if ( !this._loaders.containsKey( $scriptLoader.getPrefix() ) ) {
				
				this._loaders.add($scriptLoader.getPrefix() , $scriptLoader);
				
			}
			
		} catch (ex) {
			alert("新增'scriptLoader'时出错, : '" + $scriptLoader.getPrefix() + "' ");
		}
		
	}
	
});

ClassLoaderManager.LOCK = 1;
ClassLoaderManager.UNLOCK = 0;
